/*
 * JANN - a Java toolkit for creating arbitrary Artificial Neural Networks.
 * 
 * Copyright (c) 2009 Matthijs Snel
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.jann;

import java.util.ArrayList;
import java.util.List;

public class LayeredNeuralNet extends NeuralNet {

	private static final long serialVersionUID = 691916433408388140L;

	public static LayeredNeuralNet createStandardNet( int ins, int hiddens, int outs,
			Function transfer) {
		
		LayeredNeuralNet net = new LayeredNeuralNet();
		InputLayer in = new InputLayer(ins);
		net.addLayer(in);
		
		OutputLayer out = new OutputLayer(outs, transfer);
		net.addLayer(out);
		
		if ( hiddens > 0 ) {
			Function fun = new TanhFunction();
			Layer hid = new Layer(hiddens, fun);
			net.addLayer(hid);
			LayerLink inhid = new LayerLink(in, hid);
			LayerLink hidout = new LayerLink(hid, out);
		} else {
			LayerLink inout = new LayerLink(in, out);
		}
		
		return net;
	}
	
	private List<Layer> hiddenLayers;
	
	public LayeredNeuralNet() {
		hiddenLayers = new ArrayList<Layer>();
	}
	
	public void addLayer( Layer layer ) {
		if ( layer instanceof InputLayer )
			inputLayer = layer;
		else if ( layer instanceof OutputLayer )
			outputLayer = layer;
		else
			hiddenLayers.add(layer);
	}
	
	public void initWeights() {
		inputLayer.initWeights();
		for ( LayerLink link : inputLayer.getOutgoing() )
			link.initWeights();
		
		for ( Layer layer : hiddenLayers ) {
			layer.initWeights();
			for ( LayerLink link : layer.getOutgoing() )
				link.initWeights();
		}
		outputLayer.initWeights();
	}
	
	public void setParameters( Parameters params ) {
		inputLayer.setParameters(params);
		for ( LayerLink link : inputLayer.getOutgoing() )
			link.setParameters(params);
		
		for ( Layer layer : hiddenLayers ) {
			layer.setParameters(params);
			for ( LayerLink link : layer.getOutgoing() )
				link.setParameters(params);
		}
		outputLayer.setParameters(params);
	}
	
	public String weightsToString() {
		String s = "";
		for ( Layer l : hiddenLayers ) {
			for ( Neuron n : l.getNeurons() ) {
				for ( Link lnk : n.getIncoming() )
					s += lnk.getWeight() + " ";
				s += "\n" + n.getWeight() + "\n";
			}
			s += "\n";
		}
		for ( Neuron n : outputLayer.getNeurons() ) {
			for ( Link lnk : n.getIncoming() )
				s += lnk.getWeight() + " ";
			s += "\n" + n.getWeight() + "\n";
		}
		return s;
	}
}
